# shop.py
from playwright.sync_api import Browser,Page,sync_playwright
from lxml import etree

from config import *
from county_config import *
from tool import close_bro_byapi,add_query_parameters,excel_date_to_datetime,read_excel_with_merged_from_bytes
from playwright_tool import *
from sql import sqlseverDB
import requests,concurrent.futures
import math,traceback,logging,inspect
import shutil,string,urllib.parse
import numpy as np

class PHShop:

    def __init__(self,basic_info):
        self.basic_info=basic_info
        self.basic_info['PingTai']='菲律宾虾皮'
        self.shopid=basic_info['shopid']
        self.bid=basic_info['BrowserID']
        self.dpName=basic_info['DpName']
        self.userName = basic_info['UserName']
        self.password = basic_info['Password']
        self.gname=basic_info['GroupName']
        self.req_count=basic_info.get('req_count',0)
        self.ms = sqlseverDB('{SQL Server}', SQL_SERVER, 'sumaitongpol', SQL_USER, SQL_PWD)

    def close_browser(self,pyll:Playwright,bro:Browser):
        bid=self.bid
        bname=self.dpName
        task_id=self.task_id
        aff_close=tms.ExecNoQuery('update taskstatus set is_on=0 where bid=? and task_id=?',(bid,task_id))
        rs= tms.ExecQuery('select count(*) from taskstatus where bid=? and task_id!=? and is_on=1',(bid,task_id))
        
        if rs[0][0]==0:
            try:
                bro.close()
                pyll.stop()
                sss=close_bro_byapi(bid)
                logging.info(f'店铺:《{bname}》,{bid},关闭浏览器状态:{sss},标记is_on=0情况:{aff_close}')
            except Exception as e:
                logging.error(f'店铺:《{bname}》,{bid},关闭浏览器失败,标记is_on=0情况:{aff_close}')

        else:
            logging.info(f'店铺:{bname},{bid},有其他 {rs[0][0]} 个任务,正在运行,稍后关闭')

    def record_timestamp(self,ttt,req_count=None):
            #记录结束使用时间
        cur_timestamp=int(time.time())
        tb_name='ShopeePHAccount'
        if self.basic_info['Country']=='马来西亚':
            tb_name='Houtai'
        if ttt==1:
            aff_end=tms.ExecNoQuery(f'update {tb_name} set last_start_time={cur_timestamp} where browserid=?',(self.bid,))
            logging.info(f'店铺:《{self.dpName}》,{self.bid},记录浏览器开始时间:{aff_end}')
        elif ttt==2:
            #记录req_count和最后采集时间
            cur_timestamp=int(time.time())
            aff_end=tms.ExecNoQuery(f'update {tb_name} set last_end_time={cur_timestamp},req_count=? where browserid=?',(req_count,self.bid))
            logging.info(f'店铺:《{self.dpName}》,{self.bid},记录浏览器结束时间:{aff_end}')

    def pyb_cj_plist(self):
        '''采集虾皮产品搜索列表'''

        basic_info=self.basic_info
        country=basic_info['Country']
        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        #res_bbb= playwright_openChrome()
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        suc=0
        playyq,browser=res_bbb
        self.record_timestamp(1)
        defaultContext = browser.contexts[0]
        page = defaultContext.new_page()
        
        lmitem_list=self.task_list
        logging.info(f'店铺:《{self.dpName}》,{self.bid},需采集关键词数:{len(lmitem_list)}')
        is_no_login=False
        all_qj_count=0
        # rs_extra_params=tms.ExecQuery('select extraParam from task where id=?',(self.task_id,))
        # extra_params=json.loads(rs_extra_params[0][0]) if rs_extra_params[0][0] else None
        
        for lm_item in lmitem_list:
            pdatas=[]
            if self.req_count>=PH_MAX_REQ_COUNT:
                logging.info(f'店铺:《{self.dpName}》,{self.bid},请求次数超过{self.req_count},退出休息2小时')
                break
            
            if is_no_login:
                break
            kw=lm_item['keyword']
            lm_url=f'{Country_Host_Map[country]}/search?keyword={kw}'
            lm_url=add_query_parameters(lm_url,Country_XP_Map[country])
            # if extra_params:
            #     lm_url=add_query_parameters(lm_url,extra_params)
            
            zzid=lm_item['id']
            lm_item['lmurl']=lm_url
            api_url='/api/v4/search/search_items'
            self.basic_info['url']=lm_url
            pp=1
            max_p=9
            qj_count=0
            while True:
                if self.req_count>=PH_MAX_REQ_COUNT:
                    break
                if pp>max_p:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},关键词:《{kw}》,已请求到最大页数退出...')
                    break
                if pp==1:
                    res=wait_goto_response(page,self.basic_info,lm_url,api_url)
                    res_code=res['code']
                    if res_code!=0:
                        if res_code==-2:
                            is_no_login=True
                        break
                else:
                    el_nexp=page.locator('xpath=//a[@class="shopee-button-outline shopee-mini-page-controller__next-btn" and @aria-disabled="false"]')
                    if el_nexp.count()>0:
                        res=wait_click_response(page,self.basic_info,el_nexp,api_url)
                        res_code=res['code']
                        if res_code!=0:
                            if res_code==-2:
                                is_no_login=True
                            break
                    else:
                        logging.info(f'店铺:《{self.dpName}》,{self.bid},,关键词:《{kw}》,下一页按钮无法点击,判断为最后一页')
                        break

                js_data=res['data']
                self.req_count+=1
                qj_count+=1
                all_qj_count+=1
                if js_data.get('items'):
                    if pp==1:
                        max_pcount=js_data['total_count']
                        max_p=math.ceil(max_pcount/60)
                        logging.info(f'店铺:《{self.dpName}》,{self.bid},关键词:《{kw}》,获取类目产品最大页数:{max_p}')
                        if max_p>2:
                            max_p=2

                    pitems=js_data['items']
                    pdatas.extend(pitems)
                    suc+=len(pdatas)
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},关键词:《{kw}》,第{pp}页，获取产品总数量:{len(pitems)},当前总获取:{len(pdatas)}')
                else:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},关键词:《{kw}》,第{pp}页,出错 => {js_data}')
                    break
                sj_sec=1 + random.random() * 2
                time.sleep(sj_sec)
                pp+=1

            logging.info(f'店铺:《{self.dpName}》,{self.bid},关键词:《{kw}》,采集了{pp}页,共获取{len(pdatas)}个产品,开始存入数据表...')
            if qj_count>0:
                cur_timestamp=datetime.datetime.now()
                res_save=0
                if pdatas:
                    res_save=save_ph_pro(pdatas,lm_item,country)
                aff_lm=tms.ExecNoQuery('update keyword_1688 set is_cj=1,cj_time=? where id=?',(cur_timestamp,zzid))
                logging.info(f'店铺:《{self.dpName}》,{self.bid},关键词:《{kw}》,本次采集新产品: {res_save} 个,记录采集状态:{aff_lm}')


            # with open(f'JSONDATA/菲律宾类目{lmid}_完整.json','w',encoding='utf-8') as f:
            #     json.dump(pdatas,f,ensure_ascii=False,indent=4)
        if all_qj_count>0:
            self.record_timestamp(2,self.req_count)

        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集类目列表成功','aff':suc}

    def pyb_cj_pitem(self):
        '''采集虾皮产品详情'''

        country=self.basic_info['Country']
        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        #res_bbb= playwright_openChrome()
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        suc=0
        playyq,browser=res_bbb
        self.record_timestamp(1)
        defaultContext = browser.contexts[0]
        page = defaultContext.new_page()
        pro_list=self.task_list
        logging.info(f'店铺:《{self.dpName}》,{self.bid},分配到 {len(pro_list)} 个任务,开始采集..')
        qj_count=0
        task_count=len(pro_list)
        err_count=0
        pp=1
        for pitem in pro_list:
            if err_count>=3:
                self.close_browser(playyq,browser)
                return {'code':-1,'msg':'浏览器禁用2小时'}
            if self.req_count>=PH_MAX_REQ_COUNT:
                logging.info(f'店铺:《{self.dpName}》,{self.bid},请求次数超过{self.req_count},退出休息2小时')
                break
            pid,purl,itemid=pitem
            api_url='/api/v4/pdp/get_pc'
            self.basic_info['url']=purl
            res=wait_goto_response(page,self.basic_info,purl,api_url)
            res_code=res['code']
            if res_code!=0:
                if res_code==404:
                    cur_time=datetime.datetime.now()
                    aff_ppp=tms.ExecNoQuery('update ShopeePHADPro set is_cj=404,cj_des_time=? where id=?',(cur_time,pid))
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},页面404,标记:{aff_ppp}')
                else:
                    
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},出错 =>{res}')
                    if res_code in [-1,-2]:
                        self.close_browser(playyq,browser)
                        return res
                    err_count+=1
                task_count-=1
                pp+=1
                continue
            js_data=res['data']
            self.req_count+=1
            qj_count+=1
            if js_data.get('data'):
                pdata=js_data['data']
                cmt_list=res['cmt_list']
                cmt_max_p=res['cmt_max_p']
                pl_page=2
                wait_pl_sec=0
                if cmt_list:
                    while True:
                        el_nexp=page.locator(f'xpath=//button[@class="shopee-icon-button shopee-icon-button--right"]')
                        if el_nexp.is_visible():
                            res_pl=wait_click_response(page,self.basic_info,el_nexp,'/v2/item/get_ratings')
                            if res_pl['code']==0:
                                cmt_data=res_pl['data']
                                cur_cmt_list=cmt_data['data']['ratings']
                                cmt_list.extend(cur_cmt_list)
                                pl_page+=1
                                logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},截取第 {pl_page} 页评论 {len(cur_cmt_list)} 个,当前截取总评论数 {len(cmt_list)} 个')
                            else:
                                logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},截取第 {pl_page} 页评论失败')
                        
                        if pl_page>cmt_max_p:
                            break        
                        #page.wait_for_load_state("networkidle")
                        sj_sec=random.uniform(5,8)
                        time.sleep(sj_sec)
                        wait_pl_sec+=sj_sec
                        if wait_pl_sec>120:
                            logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},等待第 {pl_page} 页评论超时退出')
                            break

                suc+=1
                logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},成功获取产品详情接口数据')
                cmt_str=None
                if cmt_list:
                    cmt_str=json.dumps(cmt_list, ensure_ascii=False)
                res_save=save_ph_pro_deail(pdata,pitem,country,cmt_str)
                aff_ppp=0
                if res_save:
                    cur_time=datetime.datetime.now()
                    aff_ppp=tms.ExecNoQuery('update ShopeePHADPro set is_cj=1,cj_des_time=? where id=?',(cur_time,pid))
                logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},保存详请状态:{res_save},更改详情采集状态:{aff_ppp}')
            else:
                logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},获取产品详情,出错 => {js_data}')
    
            task_count-=1
            logging.info(f'店铺:《{self.dpName}》,{self.bid},剩余需采集:{task_count} 个')
            sj_sec=random.uniform(4,7)
            time.sleep(sj_sec)
            pp+=1

            # with open(f'JSONDATA/菲律宾类目{lmid}_完整.json','w',encoding='utf-8') as f:
            #     json.dump(pdatas,f,ensure_ascii=False,indent=4)

        if qj_count>0:
            self.record_timestamp(2,self.req_count)
        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集产品详情成功','aff':suc}

    def pyb_cj_dplist(self):
        '''采集菲律宾虾皮店铺列表'''

        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        #res_bbb= playwright_openChrome()
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        suc=0
        playyq,browser=res_bbb
        self.record_timestamp(1)
        defaultContext = browser.contexts[0]
        page = defaultContext.new_page()
        lmitem_list=self.lmitem_list
        is_no_login=False
        all_qj_count=0

        
        for lm_item in lmitem_list:
            pdatas=[]
            if self.req_count>=PH_MAX_REQ_COUNT:
                logging.info(f'店铺:《{self.dpName}》,{self.bid},请求次数超过{self.req_count},退出休息2小时')
                break
            
            if is_no_login:
                break
            lm_url=lm_item['ysdpurl']
            zzid=lm_item['id']
            api_url='shopee.ph/api/v4/shop/rcmd_items'
            self.basic_info['url']=lm_url
            pp=1
            max_p=9
            qj_count=0
            while True:
                if self.req_count>=PH_MAX_REQ_COUNT:
                    break
                if pp>max_p:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},已请求到最大页数退出...')
                    break
                if pp==1:
                    res=wait_goto_response(page,self.basic_info,lm_url,api_url)
                    res_code=res['code']
                    if res_code!=0:
                        if res_code==-2:
                            is_no_login=True
                        break
                else:
                    el_nexp=page.locator('xpath=//button[@class="shopee-button-outline shopee-mini-page-controller__next-btn"]')
                    if el_nexp.count()>0:
                        res=wait_click_response(page,self.basic_info,el_nexp,api_url)
                        res_code=res['code']
                        if res_code!=0:
                            if res_code==-2:
                                is_no_login=True
                            break
                    else:
                        logging.info(f'店铺:《{self.dpName}》,{self.bid},下一页按钮无法点击,判断为最后一页')
                        break

                js_data=res['data']
                self.req_count+=1
                qj_count+=1
                all_qj_count+=1
                if js_data.get('data'):
                    if pp==1:
                        max_pcount=js_data['data']['total']
                        max_p=math.ceil(max_pcount/30)
                        logging.info(f'店铺:《{self.dpName}》,{self.bid},店内获取类目产品最大页数:{max_p}')
                        if max_p>9:
                            max_p=9

                    pitems=js_data['data']['centralize_item_card']['item_cards']
                    pdatas.extend(pitems)
                    suc+=len(pdatas)
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},店内第{pp}页，获取产品总数量:{len(pitems)},当前总获取:{len(pdatas)}')
                else:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},店内第{pp}页,出错 => {js_data}')
                    break
                sj_sec=1 + random.random() * 2
                time.sleep(sj_sec)
                pp+=1

            logging.info(f'店铺:《{self.dpName}》,{self.bid},店内产品采集了{pp}页,共获取{len(pdatas)}个产品,开始存入数据表...')
            if qj_count>0:
                cur_timestamp=int(time.time())
                res_save=0
                if pdatas:
                    res_save=save_ph_dplist(pdatas,lm_item)
                aff_lm=tms.ExecNoQuery('update phlmurl set dpcj_timestamp=? where id=?',(cur_timestamp,zzid))
                logging.info(f'店铺:《{self.dpName}》,{self.bid},本次店内采集新产品: {res_save} 个,记录店铺采集时间:{aff_lm}')


            # with open(f'JSONDATA/菲律宾类目{lmid}_完整.json','w',encoding='utf-8') as f:
            #     json.dump(pdatas,f,ensure_ascii=False,indent=4)
        if all_qj_count>0:
            self.record_timestamp(2,self.req_count)

        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集类目列表成功','aff':suc}
    
    def tyb_cj_plist(self):
        '''采集阿里巴巴搜索列表'''

        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        api_url='h5api.m.1688.com/h5/mtop.relationrecommend.wirelessrecommend.recommend/2.0/'
        basic_info=self.basic_info
        dpName=self.dpName
        bid=self.bid
        playyq,browser=res_bbb
        defaultContext = browser.contexts[0]
        lmitem_list=self.lmitem_list
        page = defaultContext.new_page()
        ctj={
            'shop_name_export':'公司|厂',
            'price_export':'20-100',
            'historical_sold_export':'50-2000',
            'rating_star_export':'3-5',
            'bookedCount_export':'100-50000'
        }
        rs_tj= self.ms.ExecQuerydict('select * from ShopeeADDistribution')
        if rs_tj:
            minp_str,maxp_str=rs_tj[0]['price_export'].split('-')
            minp=int(minp_str)
            maxp=int(maxp_str)
        else:
            minp=20
            maxp=100
        for lm_item in lmitem_list:
            max_p=9

            zzkw=lm_item['keyword']
            gender=lm_item['min_gender']
            basic_info['kw']=zzkw
            basic_info['gender']=gender
            if '茶具' in zzkw:
                max_p=34
                url=f'https://s.1688.com/selloffer/offer_search.htm?keywords={zzkw}&charset=utf8&spm=a260k.home2025.searchbox.0&beginPage=1&sortType=va_sales360&descendOrder=true&filtOfferTags=21186'

            else:
                url=f'https://s.1688.com/selloffer/offer_search.htm?keywords={zzkw}&charset=utf8&spm=a260k.home2025.searchbox.0&priceStart={minp}&priceEnd={maxp}&beginPage=1&sortType=va_sales360&descendOrder=true&filtOfferTags=21186'
            if gender==4:
                max_p=2
                
            pdatas=[]
            suc=0
            is_change=False
            for p in range(1,max_p+1):

                if p==1:
                    res=wait_1688_goto_text(page,basic_info,url,api_url,120)
                else:
                    el_nexp=page.locator('xpath=//div[@class="fui-arrow fui-next"]')
                    logging.info(f'店铺:《{dpName}》,{bid},第 {p} 页,下页按钮是否可点击:{el_nexp.count()}')
                    
                    if el_nexp.count()>0:
                        res=wait_1688_click_text(page,basic_info,el_nexp,api_url,120)   
                    else:
                        logging.info(f'店铺:《{dpName}》,{bid},列表采集,下一页按钮无法点击,判断为最后一页')
                        break
                
      
                # cot=page.content()
                # if '哎呦喂，这里空空如也' in cot:
                #     logging.info(f'店铺:《{dpName}》,{bid},空页面退出')
                #     break
                if res['code']==-2:
                    logging.info(f'店铺:《{dpName}》,{bid},未登录退出采集')
                    return {'code':-2,'msg':'账号未登录,退出采集'}
                elif res['code']==0:
                    js_data=res['data']
                    if js_data=='没有相关产品':
                        is_change=True
                        break

                    pitems=js_data['data']['data']['OFFER'].get('items',[])
                    suc+=len(pitems)
                    if len(pitems)==0:
                        is_change=True
                        logging.info(f'店铺:《{dpName}》,{bid},第{p}页,产品列表为空,判断为最后一页')
                        break
                    pdatas.extend(pitems)
                    logging.info(f'店铺:《{dpName}》,{bid},第{p}页,成功采集{len(pitems)} 个产品,当前总采集数:{len(pdatas)}')
                time.sleep(random.uniform(3,5))
                
            logging.info(f'店铺:《{dpName}》,{bid},采集了 {p} 页,共:{len(pdatas)} 个产品,开始存入数据表')
            res_save=0
            aff_lm=0
            if pdatas or is_change:
                cur_timestamp=datetime.datetime.now()
                if pdatas:
                    res_save=save_1688_plist(pdatas,lm_item,ctj)
                aff_lm=tms.ExecNoQuery('update keyword_1688 set is_cj=1,cj_time=? where keyword=?',(cur_timestamp,zzkw))

            logging.info(f'店铺:《{self.dpName}》,{self.bid},关键词:《{zzkw}》(等级{gender}),本次采集新产品: {res_save} 个,更改采集状态:{aff_lm}')
        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集类目列表成功','aff':suc}
    
    def tyb_cj_pitem(self):
        '''采集阿里巴巴产品详情'''

        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        #res_bbb= playwright_openChrome()
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        suc=0
        playyq,browser=res_bbb
        defaultContext = browser.contexts[0]
        page = defaultContext.new_page()
        pro_list=self.lmitem_list

        qj_count=0
        task_count=len(pro_list)
        pp=1
        for pitem in pro_list:

            pid,purl,itemid=pitem
  
            self.basic_info['url']=purl
            res=wait_1688_des_html(page,self.basic_info,purl,120)

            res_code=res['code']
            if res_code!=0:
                if res_code==404:
                    cur_time=datetime.datetime.now()
                    aff_ppp=tms.ExecNoQuery('update S1688Pro set is_cj=404,cj_des_time=? where id=?',(cur_time,pid))
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},页面404,标记:{aff_ppp}')
                else:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},出错 =>{res}')
                    if res_code in [-1,-2]:
                        self.close_browser(playyq,browser)
                        return res
                task_count-=1
                pp+=1
                continue
            js_data=res['data']
            suc+=1
            logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},成功获取产品详情接口数据')
            if js_data.get('globalData'):
                res_save=save_1688_pro_deail2(js_data,pitem)
                
            else:
                res_save=save_1688_pro_deail(js_data,pitem)
            aff_ppp=0
            if res_save:
                cur_time=datetime.datetime.now()
                aff_ppp=tms.ExecNoQuery('update S1688Pro set is_cj=1,cj_des_time=? where id=?',(cur_time,pid))
            logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},保存详请状态:{res_save},更改详情采集状态:{aff_ppp}')

            task_count-=1
            logging.info(f'店铺:《{self.dpName}》,{self.bid},剩余需采集:{task_count} 个')
            sj_sec=random.uniform(4,7)
            time.sleep(sj_sec)
            pp+=1

        sql_str2='''
                WITH sku1_ranked AS (
                    SELECT itemid, sku1,
                        'A' + CAST(DENSE_RANK() OVER (PARTITION BY itemid ORDER BY sku1) AS VARCHAR) AS sku1BM
                    FROM S1688ProSKU where sku1BM is null
                    GROUP BY itemid, sku1
                ),

                sku2_ranked AS (
                    SELECT itemid, sku2,
                        'B' + CAST(DENSE_RANK() OVER (PARTITION BY itemid ORDER BY sku2) AS VARCHAR) AS sku2BM
                    FROM S1688ProSKU
                    WHERE sku2 IS NOT NULL and  sku1BM is null
                    GROUP BY itemid, sku2
                )

                UPDATE T
                SET 
                    T.sku1BM = S1.sku1BM,
                    T.sku2BM = CASE WHEN T.sku2 IS NULL THEN NULL ELSE S2.sku2BM END
                FROM S1688ProSKU T 
                JOIN sku1_ranked S1 ON T.itemid = S1.itemid AND T.sku1 = S1.sku1
                LEFT JOIN sku2_ranked S2 ON T.itemid = S2.itemid AND T.sku2 = S2.sku2
                WHERE T.sku1BM IS NULL;
                '''
        aff2=self.ms.ExecNoQuery(sql_str2)
        logging.info(f'更新了 {aff2} 个SKU编码')

        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集产品详情成功','aff':suc}

    def tyb_cj_order(self):

        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        #res_bbb= playwright_openChrome()
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        
        suc=0
        buy_name_yymb_map={
            '夏夏夏':{'SJBM':'cai-8897','YYBM':'id8888'},
            '印尼虾皮':{'SJBM':'cai-8897','YYBM':'id8888'},
            '办公室':{'SJBM':'cai-8897','YYBM':'id8888'},
            '泰泰泰':{'SJBM':'cai-8897','YYBM':'th8888'},
            '新加坡':{'SJBM':'cai-8897','YYBM':'sg8888'},
            '广告组':{'SJBM':'cai-8897','YYBM':'ads777'},
            '广告组 林':{'SJBM':'cai-8897','YYBM':'adslxh777'},
            '李亚超':{'SJBM':'lyc777','YYBM':'lyc777'},
            '东莞优选仓':{'SJBM':'cai-8897','YYBM':'dg8888'},
            '林向华 马来':{'SJBM':'lxh888','YYBM':'mylxh888'},
            '林向华 泰国':{'SJBM':'lxh888','YYBM':'dwlxh888'},
            '林向华 东莞':{'SJBM':'lxh888','YYBM':'dwlxh888'},
            '广告组 林向华':{'SJBM':'lxh888','YYBM':'ads666'},
        }


        playyq,browser=res_bbb
        defaultContext = browser.contexts[0]
        page = defaultContext.new_page()

        p=1
        max_page=2
        
        while True:
         
            url=f'https://air.1688.com/app/ctf-page/trade-order-list/buyer-order-list.html?oldBuyerOrderList=y&page={p}&pageSize=30'
            res=wait_1688_order_url(page,self.basic_info,url,p,timeout=300)
            res_code=res['code']
            if res_code!=0:
                if res_code in [-1,-2]:
                    self.close_browser(playyq,browser)
                    return res
                print(f'店铺:《{self.dpName}》,{self.bid},第 {p} 页,采集错误')
                continue
            
            download_url=res['data']
            order_sku_map=res['order_sku_map']
            max_page=res['max_page']
            if max_page>20:
                max_page=20
            err_count=0
            while True: 
                try:
                    res2=requests.get(download_url,timeout=200)
                    if res2.status_code==200:
                        cot=res2.content
                        break
                    else:
                        err_count+=1
                except Exception as e:
                    print(e)
                    err_count+=1
                time.sleep(human_wait())
                if err_count>0:
                    self.close_browser(playyq,browser)
                    return {'code':-3,'msg':'请求excel地址错误'}
            DD_YD_map={}
            order_list=read_excel_with_merged_from_bytes(cot)
            tb_name='S1688Order'
            with open(f'TABLEJSON/{tb_name}.json','r',encoding='utf-8') as f:
                col_to_cn=json.load(f)
            cn_tol_col={v:k for k,v in col_to_cn.items()}
            order_id_set=set()
            cur_aff=0
            cancel_count=0

            for i,order_dict in enumerate(order_list,start=1):
                if not order_dict['Offer ID'] and not order_dict['SKU ID']:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{p}页,第 {i} 个订单,无id跳过')
                    continue
                order_data={}
                ccc_oid=order_dict['订单编号']
                ccc_ddzt=order_dict['订单状态']
                if ccc_ddzt=='交易关闭':
                    cancel_count+=1
                    # logging.info(f'店铺:《{self.dpName}》,{self.bid},第{p}页,第 {i} 个订单,交易关闭跳过')
                    # continue
                #郑雨蝶订单错误填写判断
                if ccc_oid=='2619398784575443675':
                    order_dict['收货人姓名']='泰泰泰'

                ccc_pid=order_dict['Offer ID']
                ccc_skuid=order_dict['SKU ID']
                if not ccc_skuid:
                    order_dict['SKU ID']=ccc_pid
                ccc_pname=order_dict['货品标题']
                buyer_name=order_dict['收货人姓名']
                order_id_set.add(ccc_oid)

                for cn_name,cvv in order_dict.items():
                    if cn_tol_col.get(cn_name):
                        if not cvv:
                            cvv=None
                        order_data[cn_tol_col[cn_name]]=cvv
                
                if order_data.get('YunDanHao'):
                    DD_YD_map[ccc_oid]=order_data['YunDanHao']
                else:
                    order_data['YunDanHao']=DD_YD_map.get(ccc_oid)

                if order_sku_map.get((ccc_oid,ccc_skuid)):
                    target_info=order_sku_map.get((ccc_oid,ccc_skuid))
                    order_data['sku_img']=target_info.get('sku_img')
                    order_data['specId']=target_info.get('specId')
                    order_data['sku1']=target_info.get('sku1')
                    order_data['sku2']=target_info.get('sku2')
                    order_data['memo_remark']=target_info['memo_remark']
                
                if buy_name_yymb_map.get(buyer_name):
                    sjbm=buy_name_yymb_map[buyer_name]['SJBM']
                    yybm=buy_name_yymb_map[buyer_name]['YYBM']
                    order_data['SJBM']=sjbm
                    order_data['YYBM']=yybm
        
                order_data['bid']=self.bid
                order_data['bname']=self.dpName
                
                zds=list(order_data.keys())
                paras=list(order_data.values())
                aff=self.ms.merge_into(tb_name,zds,paras,['DingDanBianHao','Skuid'],True)
                #aff=1
                if aff:
                    cur_aff+=1
                    suc+=aff
                logging.info(f'店铺:《{self.dpName}》,{self.bid},第{p}页,第 {i} 个订单,存入情况:{aff}')
            logging.info(f'店铺:《{self.dpName}》,{self.bid},第{p}页,共采集 {len(order_id_set)} 个订单编号,{len(order_list)} 个订单,保存 {cur_aff} 行,交易关闭:{cancel_count}')
            if p>=max_page:
                logging.info(f'店铺:《{self.dpName}》,{self.bid},已经采集完最后一页,共保存 {suc} 行订单,退出')
                break
            p+=1
            time.sleep(human_wait(min_seconds=5,max_seconds=10))

        page.close()   
        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集采购单成功','aff':suc}

    def tyb_bcj_pitem(self):
        '''1688补充采集产品'''

        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        #res_bbb= playwright_openChrome()
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        suc=0
        playyq,browser=res_bbb
        defaultContext = browser.contexts[0]
        page = defaultContext.new_page()
        pro_list=self.offerid_list

        task_count=len(pro_list)
        pp=1
        for pitem in pro_list:

            itemid=pitem[0]
            only_sku=False
            purl=f'https://detail.1688.com/offer/{itemid}.html'
            if not hasattr(self,'is_recj'):
                rs_has=tms.ExecQuery('select count(*) from s1688pro where itemid=?',(itemid,))
                if rs_has[0][0]>0:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:《{itemid}》,已存在跳过')
                    continue
            else:
                only_sku=True
            self.basic_info['url']=purl
            res=wait_1688_des_html(page,self.basic_info,purl,120)

            res_code=res['code']
            if res_code!=0:
                if res_code==404:
                    cur_time=datetime.datetime.now()
                    aff_ppp=tms.ExecNoQuery('update S1688Pro set is_cj=404,cj_des_time=? where itemid=?',(cur_time,itemid))
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},页面404,标记:{aff_ppp}')
                else:
                    logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},出错 =>{res}')
                    if res_code in [-1,-2]:
                        self.close_browser(playyq,browser)
                        return res
                task_count-=1
                pp+=1
                continue
            js_data=res['data']
            suc+=1
            logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},成功获取产品详情接口数据')
            if js_data.get('globalData'):
                res_save=save_allzd_1688_pro_deail2(js_data,pitem,only_sku)
                
            else:
                res_save=save_allzd_1688_pro_deail(js_data,pitem,only_sku)
            aff_ppp=0
            if res_save:
                cur_time=datetime.datetime.now()
                aff_ppp=tms.ExecNoQuery('update S1688Pro set is_cj=1,cj_des_time=? where itemid=?',(cur_time,itemid))
            logging.info(f'店铺:《{self.dpName}》,{self.bid},第{pp}个itemid:{itemid},保存详请状态:{res_save},更改详情采集状态:{aff_ppp}')

            task_count-=1
            logging.info(f'店铺:《{self.dpName}》,{self.bid},剩余需采集:{task_count} 个')
            sj_sec=random.uniform(4,7)
            time.sleep(sj_sec)
            pp+=1

        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集产品详情成功','aff':suc}

    def tyb_cj_wl(self):

        '''采集1688订单物流'''
        bid=self.bid
        bname= self.dpName
        sql_str=f'''select DingDanBianHao,min(SJBM),min(YYBM) from S1688Order where is_cj_wl=0 and bid='{bid}' 
                    and YYBM is not null group by DingDanBianHao order by max(DingDanChuangJianTime) desc'''
        
        rs=self.ms.ExecQuery(sql_str)
        if len(rs)==0:
            logging.info(f'店铺:《{bname}》,{bid},没有需要采集物流信息的订单跳过')
            return {'code':0,'msg':'','aff':0}
        else:
            logging.info(f'店铺:《{bname}》,{bid},还需采集 {len(rs)} 个订单物流信息')
        res_bbb = playwright_connect_browser(self.basic_info,self.task_id)
        #res_bbb= playwright_openChrome()
        if not res_bbb:
            return {'code':-1,'msg':'启动浏览器失败'}
        
        suc=0

        playyq,browser=res_bbb
        defaultContext = browser.contexts[0]
        page = defaultContext.new_page()


        
        for oj,oitem in enumerate(rs[:50],start=1):
            DingDanBianHao,sjbm,yybm=oitem
            url=f'https://air.1688.com/app/ctf-page/trade-order-detail/index.html?orderId={DingDanBianHao}'
            res=wait_1688_wuliu_url(page,self.basic_info,[oj,sjbm,yybm],url,timeout=300)
            res_code=res['code']
            if res_code!=0:
                if res_code in [-1,-2]:
                    self.close_browser(playyq,browser)
                    return res
                print(f'店铺:《{bname}》,{bid},第{oj}个订单号:《{DingDanBianHao}》,采集错误')
                continue

            tdatas=res['data']
            WuLiuZT=res['WuLiuZT']
            order_status=res['order_status']
            if order_status:
                if order_status=='交易关闭':
                    aff_wlzt=self.ms.ExecNoQuery('update S1688Order set is_cj_wl=?,WuLiuZT=? where DingDanBianHao=?',(1,order_status,DingDanBianHao))
                    logging.info(f'店铺:《{bname}》,{bid},第{oj}个订单号:《{DingDanBianHao}》,交易关闭,标记状态:{aff_wlzt}')
            else:
                aff=0
                aff_wlzt=0
                is_cj_wl=0
                for tdata in tdatas:
                    zds=list(tdata.keys())
                    paras=list(tdata.values())
                    aff+=self.ms.merge_into('S1688WuLiu',zds,paras,['YunDanHao','traceId'],True)
                
                if aff==len(tdatas) and WuLiuZT=='已签收':
                    is_cj_wl=1

                aff_wlzt=self.ms.ExecNoQuery('update S1688Order set is_cj_wl=?,WuLiuZT=? where DingDanBianHao=?',(is_cj_wl,WuLiuZT,DingDanBianHao))
                logging.info(f'店铺:《{bname}》,{bid},第{oj}个订单号:《{DingDanBianHao}》,更新物流:{aff},标记物流状态:{aff_wlzt},是否更改采集状态:{is_cj_wl}')
            logging.info(f'店铺:《{bname}》,{bid},剩余需采集订单号:{len(rs)-oj}/{len(rs)}')
            time.sleep(human_wait(min_seconds=7,max_seconds=12))
        page.close()   
        self.close_browser(playyq,browser)
        return {'code':0,'msg':'采集采购单成功','aff':suc}

    def update_taskStatus(self,tstate,err_msg=None,is_cl=1):

        end_zds=['bid','task_id','task_name','bname','gname','state','err_msg']
        end_params=[self.bid,self.task_id,self.rw_name,self.dpName,self.gname,tstate,err_msg]
        if is_cl==0:
            end_zds.append('is_cl')
            end_params.append(is_cl)
        err_str=f'错误信息:{err_msg},' if err_msg else ''
        aff_rw=tms.merge_into('taskStatus',end_zds,end_params,['bid','task_id'],True)
        logging.info(f'店铺:《{self.dpName}》,{self.bid} 任务:《{self.rw_name}》,{err_str}标记状态:{aff_rw}')
        
    def start_task(self,task_id):
        rw_name=Task_Name_dict[task_id]
        fun_name=Task_Fuc_dict[task_id]
        self.task_id=task_id
        self.rw_name=rw_name

        try:             
            func = getattr(self, fun_name)
            res=func()
            code=res['code']
            msg=res['msg']
            if code==0:
                self.update_taskStatus(1)
            else:
                self.update_taskStatus(0,err_msg=msg,is_cl=0)
                country= self.basic_info.get('Country')
                if country:
                    if country == '菲律宾':
                        tbname='ShopeePHAccount'
                    else:
                        tbname='Houtai'
                    if code in [-2]:
                        cur_timestamp=int(time.time())
                        last_end_time=cur_timestamp+14400
                        self.ms.ExecNoQuery(f'update {tbname} set last_end_time={last_end_time},req_count={PH_MAX_REQ_COUNT} where BrowserID=?',(self.bid,))
            return res
        
        except Exception as e:
            close_SunBrowser(self.bid,task_id)
            traceback.print_exc()
            self.update_taskStatus(0,err_msg=str(e),is_cl=0)